package com.mindskip.xzs.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mindskip.xzs.domain.dto.KeyValue;
import com.mindskip.xzs.domain.dto.admin.user.UserCreateDTO;
import com.mindskip.xzs.domain.dto.admin.user.UserPageDTO;
import com.mindskip.xzs.domain.dto.student.user.UserRegisterDTO;
import com.mindskip.xzs.domain.dto.student.user.UserUpdateStudentDTO;
import com.mindskip.xzs.domain.entity.User;
import com.mindskip.xzs.domain.entity.UserEventLog;
import com.mindskip.xzs.domain.enums.RoleEnum;
import com.mindskip.xzs.domain.enums.UserStatusEnum;
import com.mindskip.xzs.domain.vo.admin.user.UserVO;
import com.mindskip.xzs.domain.vo.student.user.UserEventLogVO;
import com.mindskip.xzs.event.UserEvent;
import com.mindskip.xzs.properties.MyProperties;
import com.mindskip.xzs.repository.UserMapper;
import com.mindskip.xzs.service.UserEventLogService;
import com.mindskip.xzs.service.UserService;
import com.mindskip.xzs.utility.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends BaseServiceImpl<User> implements UserService {

    private final UserMapper userMapper;

    private final MyProperties myProperties;

    private final ApplicationEventPublisher applicationEventPublisher;

    private final UserEventLogService userEventLogService;

    public UserServiceImpl(UserMapper userMapper, MyProperties myProperties, ApplicationEventPublisher applicationEventPublisher, UserEventLogService userEventLogService) {
        super(userMapper);
        this.userMapper = userMapper;
        this.myProperties = myProperties;
        this.applicationEventPublisher = applicationEventPublisher;
        this.userEventLogService = userEventLogService;
    }

    @Override
    public User getUserByUserName(String username) {

        return userMapper.getUserByUserName(username);
    }

    @Override
    public PageInfo<UserVO> getUserByPage(UserPageDTO userPageDTO) {
        //自动的对PageHelper.startPage 方法下的第一个sql查询进行分页，给其拼接sql语句
//        PageHelper.startPage(userPageDTO.getPageIndex(), userPageDTO.getPageSize(), "id desc");
//        List<User> userList = userMapper.selectUserPage(userPageDTO);
//        PageInfo<User> oldPageInfo = new PageInfo<>(userList);
        PageInfo<User> oldPageInfo = PageHelper.startPage(userPageDTO.getPageIndex(), userPageDTO.getPageSize(), "id desc")
                .doSelectPageInfo(() -> userMapper.selectUserPage(userPageDTO));

        // 将 List<User> 转换为 List<UserVO>
        List<UserVO> userVOList = oldPageInfo.getList()
                .stream()
                .map(new Function<User, UserVO>() {
                    @Override
                    public UserVO apply(User user) {
                        return UserVO.from(user);
                    }
                })
                .collect(Collectors.toList());

        // 将 oldPageInfo 中的所有属性赋值到 PageInfo<UserVO> 对象，并更改该对象的List属性为 userVOList
        return PageInfoUtil.copyMap(oldPageInfo, userVOList);
    }

    // 插入或者更新用户信息
    @Override
    public User insertOrUpdateUser(UserCreateDTO userCreateDTO) {
        if (userCreateDTO.getId() == null) {
            // id为空，说明是创建一个新用户

            if (userCreateDTO.getPassword() == null) {
                throw new RuntimeException("密码不能为空喔");
            }

            if (!ObjectUtils.isEmpty(getUserByUserName(userCreateDTO.getUserName()))){
                throw new RuntimeException("用户名已存在喔");
            }

            // 判断 userCreateDTO 中 String 类型的 birthDay 属性是否为正确的日期格式
            if (!DateTimeUtil.isValidDateShortFormat(userCreateDTO.getBirthDay())) {
                // 如果 userCreateDTO 中 String 类型的 birthDay 属性为""或者" "或者格式错误，则转换为 User 中的 Date 类型的 birthDay 属性会报错
                // 所以 userCreateDTO 中 String 类型的 birthDay 属性为""或者" "或者格式错误，则将其属性设为 null
                userCreateDTO.setBirthDay(null);
            }

            //将 UserCreateDTO 转换为 User
            User user = BeanCopyUtils.copyBean(userCreateDTO, User.class);

            // 对密码进行编码
            String encodePwd = RsaUtil.rsaEncode(myProperties.getPwdKey().getPublicKey(), userCreateDTO.getPassword());
            user.setPassword(encodePwd);
            user.setUserUuid(UUID.randomUUID().toString());
            user.setCreateTime(new Date());
            user.setLastActiveTime(new Date());
            user.setDeleted(false);
            userMapper.insertSelective(user);

            return user;
        }else {
            // id 不为空，说明是更新用户
            if (!StringUtils.isBlank(userCreateDTO.getPassword())) {
                // 如果密码不为空，则说明用户要更新密码，则将密码进行编码并存到数据库
                String encodePwd = RsaUtil.rsaEncode(myProperties.getPwdKey().getPublicKey(), userCreateDTO.getPassword());
                userCreateDTO.setPassword(encodePwd);
            }

            // 判断 userCreateDTO 中 String 类型的 birthDay 属性是否为正确的日期格式
            if (!DateTimeUtil.isValidDateShortFormat(userCreateDTO.getBirthDay())) {
                // 如果 userCreateDTO 中 String 类型的 birthDay 属性为""或者" "或者格式错误，则转换为 User 中的 Date 类型的 birthDay 属性会报错
                // 所以 userCreateDTO 中 String 类型的 birthDay 属性为""或者" "或者格式错误，则将其属性设为 null
                userCreateDTO.setBirthDay(null);
            }

            //将 UserCreateDTO 转换为 User
            User user = BeanCopyUtils.copyBean(userCreateDTO, User.class);
            // BeanUtils 无法将 String 类型的属性转换为 Date 类型，所以需要手动转换
            user.setModifyTime(new Date());
            userMapper.updateByPrimaryKeySelective(user);

            return user;
        }
    }

    // 软删除
    @Override
    public void softDeleteById(Integer id) {

        User user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            throw new RuntimeException("无法查询到数据");
        }
        user.setDeleted(true);
        userMapper.updateByPrimaryKeySelective(user);
    }

    // 改变用户状态
    @Override
    public Integer changeStatus(Integer id) {
        User user = selectById(id);
        UserStatusEnum userStatusEnum = UserStatusEnum.fromCode(user.getStatus());
        Integer newStatus = userStatusEnum == UserStatusEnum.Enable ? UserStatusEnum.Disable.getCode() : UserStatusEnum.Enable.getCode();
        user.setStatus(newStatus);
        user.setModifyTime(new Date());
        updateByIdFilter(user);
        userMapper.updateByPrimaryKeySelective(user);

        return newStatus;
    }

    @Override
    public List<KeyValue> selectByUserName(String userName) {
        return userMapper.selectByUserName(userName);
    }

    @Override
    public List<User> selectByIds(List<Integer> ids) {
        return userMapper.selectByIds(ids);
    }

    public void studentRegister(UserRegisterDTO userRegisterDTO) {
        User existUser = userMapper.getUserByUserName(userRegisterDTO.getUserName());
        if (existUser != null) {
            throw new RuntimeException("用户已存在");
        }

        User user = BeanCopyUtils.copyBean(userRegisterDTO, User.class);
        //对密码进行编码
        String encodePwd = RsaUtil.rsaEncode(myProperties.getPwdKey().getPublicKey(), userRegisterDTO.getPassword());
        user.setUserUuid(UUID.randomUUID().toString());
        user.setPassword(encodePwd);
        user.setRole(RoleEnum.STUDENT.getCode());
        user.setStatus(UserStatusEnum.Enable.getCode());
        user.setLastActiveTime(new Date());
        user.setCreateTime(new Date());
        user.setDeleted(false);

        int i = userMapper.insertSelective(user);
        if (i <= 0) {
            throw new RuntimeException("插入用户失败");
        }

        UserEventLog userEventLog = new UserEventLog(user.getId(), user.getUserName(), user.getRealName(), new Date());
        userEventLog.setContent("欢迎 " + user.getUserName() + " 注册来到学之思开源考试系统");

        applicationEventPublisher.publishEvent(new UserEvent(userEventLog));
    }

    @Override
    public List<UserEventLogVO> log(User user) {
        List<UserEventLog> userEventLogs = userEventLogService.getUserEventLogByUserId(user.getId());

        return userEventLogs.stream()
                .map(userEventLog -> {
                    UserEventLogVO userEventLogVO = BeanCopyUtils.copyBean(userEventLog, UserEventLogVO.class);

                    userEventLogVO.setCreateTime(DateTimeUtil.dateFormat(userEventLog.getCreateTime()));
                    return userEventLogVO;
                })
                .collect(Collectors.toList());
    }

    @Override
    public void updateUser(UserUpdateStudentDTO userUpdateStudentDTO, User user) {

        if (StringUtils.isBlank(userUpdateStudentDTO.getBirthDay())) {
            userUpdateStudentDTO.setBirthDay(null);
        }
        User newUser = selectById(user.getId());
        BeanUtils.copyProperties(userUpdateStudentDTO, newUser);
        newUser.setBirthDay(DateTimeUtil.parse(userUpdateStudentDTO.getBirthDay(), DateTimeUtil.STANDER_SHORT_FORMAT));
        newUser.setModifyTime(new Date());
        System.out.println(newUser);
        int i = userMapper.updateByPrimaryKeySelective(newUser);
        if (i <= 0) {
            throw new RuntimeException("更新学生用户信息失败");
        }

        UserEventLog userEventLog = new UserEventLog(user.getId(), user.getUserName(), user.getRealName(), new Date());
        userEventLog.setContent(user.getUserName() + " 更新了个人资料");
        applicationEventPublisher.publishEvent(new UserEvent(userEventLog));

    }
}
